﻿/*
  Copyright (c) 2011, Mikheev Rostislav
  Copyright (c) 2011, FreshFarsh team

  Steel Engine source code is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
/**
  @author Mikheev Rostislav <hacenator@gmail.com>
  @date 23.03.2011
  @brief Window manager class header file
*/

#ifndef STEEL_WINDOWS_MANAGER_H_
#define STEEL_WINDOWS_MANAGER_H_

#include <list>
#include <stdint.h>

//#include <windows.h> // commented while linux poring
//#include <wingdi.h> // commented while linux porting

#include <GL/glew.h>
//#include <GL/wglew.h> // commented while linux porting
#include <GL/glu.h>
#include <SDL/SDL.h>
#include "common.h"
#include "structures.h"
#include "system.h"
#include "basic_class.h"

namespace _STEEL_NAMESPACE {

//typedef void (__stdcall * unknownCallback)(); ///< Unknown Callback
typedef bool (*InitCallback)(); ///< Application Initialization Callback
typedef void (*DrawCallback)(); ///< Frame Draw callback
typedef void (*CloseCallback)(); ///< Application terminate callback
typedef void (*KeyUpCallback)(int key); ///< Keyboard key up callback
typedef void (*KeyDownCallback)(int key); ///< Keyboard key down callback
typedef void (*MouseMoveCallback)(int x, int y); ///< Mouse move
typedef void (*MouseUpCallback)(int x, int y, int button); ///< Mouse up
typedef void (*MouseDownCallback)(int x, int y, int button); ///< Mouse up

//TODO(hacenator): problem with 64bits systems?
typedef uint32_t VariantCallback; ///< callback address
typedef uint32_t ListenerId; ///< listener identificator


class WindowManager : public BasicClass {
 public:
 /**
  * Events to listen
  */
  enum ListenerEvent {
    kListenKeyUp, ///< keyboard Key Up event
    kListenKeyDown, ///< keyboard key down event
    kListenMouseMove, ///< mouse move event
    kListenMouseUp, ///< mouse button up event
    kListenMouseDown, ///< mouse button down event

    // application events
    kListenInit, ///< application initialization event
    kListenDraw, ///< application frame draw event
    kListenClose ///< application close event
  };

  /**
   * Type of listener
   */
  enum ListenerType {
    kListenerFunction,
    kListenerObject
  };

  WindowManager();
  ~WindowManager();

  void OpenWindow(int width, int height, bool fullscreen);

  // events
  /**
   *  Add listener to specified event
   *  @param callaback
   *      Function called when event is occured
   *  @param event
   *      Event type
   *  @return
   *      Listener id
   */
  ListenerId AddListener(VariantCallback callback, ListenerEvent event);

  /**
   *  Add listener to specified event
   *  @param listenerObject
   *      Object listener
   *  @param event
   *      Event type
   *  @return
   *      Listener id
   */
  ListenerId AddListener(void *object, ListenerEvent event);

  /**
   *  Remove listener
   *  @param listenerId
   *      Identificator of listener to remove
   *  @param
   *      Return true if listener is removed, false otherwise
   */
  bool RemoveListener(ListenerId id);

  //TODO: Freeze listener?

  // config
  void SetAntialiasingSamples(int samples);

  // Get
  int fps();

  int width();

  int height();

  float mouse_sensetive();

  // Set
  void set_mouse_sensetive(float value);

  //
  bool IsActive();
  bool IsOpened();
 private:
  /**
   * Event Listener
   */
  struct EventListener {
    ListenerId id; ///< listener unified identificator
    VariantCallback callback; ///< callback
    ListenerEvent event; ///< type of listenen event
    ListenerType listener; ///< type of listener
  };

  std::list<EventListener> _listeners;
  ListenerId _last_listener_id; ///< identificator of last added listener

  void ClearListeners();


  // parameters
  int _width; ///< windows width
  int _height; ///< windows height
  int _bpp; ///< bites per pixel
  bool _fullscreen; ///< windows fullscreen mode
  bool _done; ///< application done flag

  // input parameters
  float _mouse_sensetive; ///< mouse sensetive

  /* FPS */
  int _last_fps;
  int _frames;
  int _fps;

  /* Multisample Antialiasing MSAA */
  bool _antialiasing; ///< enabled or not
  uint16_t _antialiasing_samples; ///< samples count

  /**/

  bool InitOpenGL();
  void BeginMainLoop();

  inline void ProcessKeyboard(const SDL_KeyboardEvent *key);
  inline void ProcessMouseButton(const SDL_MouseButtonEvent *button);
  inline void ProcessMouseMove(const SDL_MouseMotionEvent *move);
  void ProcessEvents();
  void ProcessDrawing();

  Point2i GetMousePosition();
};

}

#endif // _H_STEEL_WINDOWS_MANAGER
